package org.example.framework;

import org.example.demo.Number;
import org.example.demo.Person;
import org.example.framework.BeanDefinition;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MiniApplicationContext {
    private String xml_file;
    private BeanDefinitionReader reader=new BeanDefinitionReader();
    private Map<String,Object> beans;
    public Map<String,Object> getBeans(){
        return beans;
    }

    public MiniApplicationContext(String xml_file) throws MiniApplicationException{
        this.xml_file=xml_file;
        beans=new HashMap<>();
        reader.getBeanDefinitions(xml_file);
    }
    public Object getBean(String id) throws MiniApplicationException{
        //判断容器内是否含有要找的bean对象，有就直接返回
        Object obj=beans.get(id);
        if(obj!=null){
            return obj;
        }
        BeanDefinition def=reader.getBeanDefinitionMap().get(id);
        if(def==null){
            throw new MiniApplicationException(MiniApplicationException.ErrorType.BEAN_NOTFOUND,"未找到bean对象的id");

        }
        Object[] args = new Object[def.getConstructorArgs().size()];
        Constructor<?> constructor = resolveConstructor(def, args);
        injectProperties(def);
        //创建Bean对象
        //利用反射创建对象，并注入属性
        try{
            Object object = constructor.newInstance(args);
            beans.put(def.getBeanName(),object);
        beans.put(id,object);
        return object;
        }
        catch (InstantiationException e) {
            throw new MiniApplicationException(MiniApplicationException.ErrorType.CREATE_OBJECT_ERROR, "创建对象失败：请检查是否有无参构造函数");
        } catch (IllegalAccessException e) {
            throw new MiniApplicationException(MiniApplicationException.ErrorType.CREATE_OBJECT_ERROR, "创建对象失败：类不能是抽象类，无参构造函数不能为私有");
        }
        catch (Exception e){
            throw new MiniApplicationException(MiniApplicationException.ErrorType.CREATE_OBJECT_ERROR,"创建对象失败：构造方法错误");
        }

    }
    private void injectProperties(BeanDefinition bd) throws MiniApplicationException {
        if(bd.getBeanClass()==null) { return;}
        Method[] methods = bd.getBeanClass().getMethods();
        try {
            for (Method method : methods) {
                if (method.getParameterCount() != 1 || !method.getName().startsWith("set")) {
                    continue;
                }
                for (Property beanProperty : bd.getPropertyList()) {
                    if (!method.getName().equalsIgnoreCase("set" + beanProperty.getName())) {
                        continue;
                    }
                    Class<?> type = method.getParameters()[0].getType();
                    Object value= null;
                    if (beanProperty.getValue() != null) {
                        value = convertPrimaryValue(beanProperty.getValue(), type);
                    }else if(beanProperty.getRef()!=null){
                        value = beans.get(beanProperty.getRef());
                    }
                    if(value!=null){
                        method.invoke(beans.get(bd.getBeanName()), value);
                    }
                }
            }
        } catch (Exception e) {
            throw new MiniApplicationException(MiniApplicationException.ErrorType.CREATE_OBJECT_ERROR,
                    "Create Bean '" + bd.getBeanName() + "' error. " + e.getMessage());
        }
    }
    /**
     * 将value字符串解析为具体值
     * @param valueStr
     * @param type
     * @return
     */
    private static Object convertPrimaryValue(String valueStr, Class<?> type) {
        Object value = (type == int.class||type == Integer.class) ? Integer.parseInt(valueStr)
                : (type == long.class||type == Long.class) ? Long.parseLong(valueStr)
                : (type == float.class||type == Float.class) ? Float.parseFloat(valueStr)
                : (type == String.class) ? valueStr : null;
        return value;
    }
    private Constructor<?> resolveConstructor(BeanDefinition beanDefinition, Object[] args) throws MiniApplicationException {
        try {
            List<ConstructorArg> BeanArgs = beanDefinition.getConstructorArgs();
            if (BeanArgs.isEmpty()) {
                return beanDefinition.getBeanClass().getConstructor();
            }

            //解析形参类型paramTypes与实参args
            Class<?>[] paramTypes=new Class[BeanArgs.size()];
            for (ConstructorArg beanArg : BeanArgs) {
                Integer index = beanArg.getIndex();
                if(index ==null){
                    throw new UnsupportedOperationException("ConstructorArg without index is unsupported  by now.");
                }
                paramTypes[index] =beanArg.getType();
                if(beanArg.getValue()!=null){
                    args[index]=convertPrimaryValue(beanArg.getValue(),paramTypes[index]);
                }else if(beanArg.getRef()!=null){
                    args[index]= beans.get(beanArg.getRef());
                }
            }

            //匹配构造函数
            for (Constructor<?> constructor : beanDefinition.getBeanClass().getConstructors()) {
                Class<?>[] parameterTypes = constructor.getParameterTypes();
                if(parameterTypes.length!=BeanArgs.size()) {continue;}
                boolean matched=true;
                for (int i = 0; i < parameterTypes.length; i++) {
                    if(parameterTypes[i].equals(paramTypes[i])) {continue;} //如果参数匹配
                    if(args[i]!=null && parameterTypes[i].isInstance(args[i])) {continue;} //如果ref的Bean的类型匹配
                    matched=false;
                    break;
                }
                if(matched) {
                    return constructor;
                }
            }
            throw new MiniApplicationException(MiniApplicationException.ErrorType.CREATE_OBJECT_ERROR,
                    "Bean creation error for '"+beanDefinition.getBeanName()+"': no coustructor found in Class" + beanDefinition.getBeanClass().getName());

        } catch (NoSuchMethodException e) {
            throw new MiniApplicationException(MiniApplicationException.ErrorType.CREATE_OBJECT_ERROR,
                    "Bean creation error for '"+beanDefinition.getBeanName()+"': no coustructor found in Class" + beanDefinition.getBeanClass().getName());
        }

    }
}
